#include "menu.h"
#include "u_Key.h"
#include "string.h"
#include "Flash_Eeprom.h"

uint8_t Get_NameLen(char *String);
// 读取上、下键
int8_t menu_Roll_event(void) // 菜单滚动
{
	if (Key_Up_Get())
	{
		return 1;
	}
	if (Key_Down_Get())
	{
		return -1;
	}
	return 0;
}
int8_t menu_Enter_event(void) // 菜单确认
{
	return Key_Enter_Get(); // 确认键接到PB14;
}
int8_t menu_Back_event(void) // 菜单返回
{
	return Key_Back_Get();
}

enum CursorStyle CurStyle = reverse;
int8_t CursorRollSpeed = 8; // 光标 动画滚动速度系数;
float MenuRollSpeed = 2;	// 菜单 动画滚动速度系数;

int8_t MenuIndex = 1;	  // 菜单索引
int8_t CursorIndex = 0;	  // 光标索引(屏幕显示区域)
int8_t ErrorCountNow = 0; // 偏差量
int8_t MenuMaxNum = 0;	  // 选项数量
int8_t Roll_Event = 0;	  // 按键标志(上、下)
int8_t RollY_Num = 0;	  // Y轴滚动量
int8_t ErrorCountPre = 0; // 前一刻偏移量

uint8_t Ui_InitFlag = 0;	// 初始化UI标志位
uint8_t SetRunListFlag = 0; // 设置目录运行标志位 =0运行主页面，=1运行设置界面
uint8_t DataAlterFlag = 0;	// 数据改动标志位

float CursorLenNow = 0;	 // 光标 实时 宽度
float CursorLenNext = 0; // 光标 目标 宽度
float CursorY_Now = 0;	 // 光标 实时 Y轴坐标
float CursorY_Next = 0;	 // 光标 目标 Y轴坐标
float StripY_Now = 0;	 // 进度条弹窗 实时 Y轴坐标
float StripY_Next = 66;	 // 进度条弹窗 目标 Y轴坐标

Menu_t *SetRunList; // 正在运行的设置目录

// 更新数据
uint8_t update_Data(char *name, uint16_t data)
{
	char chinese_part[2 * 8]; // 用于存储中文部分的数组
	char result_str[24];	  // 用于存储最终结果的数组
	char hex_value[5 + 1];	  // 用于存储AA的十六进制表示的数组

	char *bracket_pos = strchr(name, '('); // 查找'('字符的位置
	if (bracket_pos != NULL)			   // 如果找到了
	{
		uint8_t chinese_len = bracket_pos - name; // 中文长度
		strncpy(chinese_part, name, chinese_len); // 复制
		chinese_part[chinese_len] = '\0';		  // 确保字符串正确终止

		// 将数据的十进制格式化成字符串
		if (data < 10)
			snprintf(hex_value, sizeof(hex_value), "%01d", data);
		else if (data < 100)
			snprintf(hex_value, sizeof(hex_value), "%02d", data);
		else if (data < 1000)
			snprintf(hex_value, sizeof(hex_value), "%03d", data);
		else
			snprintf(hex_value, sizeof(hex_value), "%04d", data);

		snprintf(result_str, sizeof(result_str), "%s(%s)", chinese_part, hex_value); // 构造最终字符串  拼接数据

		memcpy(name, result_str, strlen(result_str) + 1); // 将最终字符串返回给name

		return 1;
	}
	else
	{
		// printf("未找到'['字符\n");
	}
	return NULL;
}

// 桌面显示
void OLED_Desktop_Show(void (*event)(void))
{
	if (SetRunListFlag == 0) // 如果设置菜单不显示
	{
		event();
	}
}
// 菜单初始化
void OLED_Menu_Init(Menu_t *option)
{
	MenuIndex = 1;
	CursorIndex = 0;
	ErrorCountNow = 0;
	MenuMaxNum = 0;
	Roll_Event = 0;

	while (option[++MenuMaxNum].Name[0] != '.') // 获取条目数量,如果文件名开头为'.'则为结尾;
		;
	MenuMaxNum--; // 不打印".."

	for (int8_t i = 0; i <= MenuMaxNum; i++) // 计算选项名宽度;
	{
		option[i].NameLen = Get_NameLen(option[i].Name);
	}

	CursorLenNow = 0;  // 实时——宽度
	CursorLenNext = 0; // 目标——宽度
	CursorY_Now = 0;   // 实时——Y轴坐标
	CursorY_Next = 0;  // 目标——Y轴坐标

	RollY_Num = 0;				// 参与光标Y轴运算
	ErrorCountPre = MenuMaxNum; // 显示动画相关;
}
// 菜单主运行函数
void OLED_Menu_Show(Menu_t *option)
{
	if (SetRunListFlag == 0)
	{
		return;
	}

	if (Ui_InitFlag == 0) // 初始化标志
	{
		OLED_Menu_Init(option); // 对菜单进行初始化
		Ui_InitFlag = 1;		// 防止初始化多次
	}

	// OLED_Clear(); // 将OLED显存数组全部清零
	if (DataAlterFlag == 0)
		Roll_Event = menu_Roll_event(); // 获取按键是否被按下 -1也是可以被执行的

	if (Roll_Event) // 如果有按键事件;
	{
		CursorIndex += Roll_Event; // 更新下标
		MenuIndex += Roll_Event;

		// 菜单索引限制
		if (MenuIndex < 0)
		{
			MenuIndex = 0;
		}
		if (MenuIndex > MenuMaxNum)
		{
			MenuIndex = MenuMaxNum;
		}

		// 光标索引限制
		if (CursorIndex < 0)
		{
			CursorIndex = 0;
		}
		if (CursorIndex > 3)
		{
			CursorIndex = 3;
		}
		if (CursorIndex > MenuMaxNum)
		{
			CursorIndex = MenuMaxNum;
		}
	}

	/**********************************************************/
	/*显示相关*/

#if 1
	// 显示区域菜单里每个选项的显示
	ErrorCountNow = MenuIndex - CursorIndex; // 计算现在的偏差量

	if (1) // 加显示动画
	{
		// if (ErrorCountNow - ErrorCountPre) // 偏差量发生变动(或者可以用 ErrorCountNow != ErrorCountPre 表示)
		if (ErrorCountNow != ErrorCountPre) // 偏差量发生变动(或者可以用 ErrorCountNow != ErrorCountPre 表示)
		{
			RollY_Num = (ErrorCountNow - ErrorCountPre) * WORD_H; //
			ErrorCountPre = ErrorCountNow;						  // 更新偏差
		}
		if (RollY_Num)
		{
			RollY_Num /= MenuRollSpeed; // 假如需要滚动，滚动偏移量按照8、4、2、1、0变化
		} // 滚动变化量: 2 快速, 1.26 较平滑;
	}

	for (int8_t i = 0; i < 5; i++) // 显示需要显示的选项名，因为屏幕上只能显示4行
	{
		if (ErrorCountNow + i > MenuMaxNum)
		{
			break;
		}

		OLED_ShowString(2, (i * WORD_H) + RollY_Num, option[ErrorCountNow + i].Name, OLED_8X16);

		char *colon_pos = strchr(option[ErrorCountNow + i].Name, ':'); // 找到 ':' 的位置
		if (colon_pos != NULL)
		{
			if (option[ErrorCountNow + i].Data < 10)
			{
				OLED_ShowNum(128 - 1 * 8, i * WORD_H, option[ErrorCountNow + i].Data, 1, OLED_8X16);
			}
			else if (option[ErrorCountNow + i].Data < 100)
			{
				OLED_ShowNum(128 - 2 * 8, i * WORD_H, option[ErrorCountNow + i].Data, 2, OLED_8X16);
			}
			else if (option[ErrorCountNow + i].Data < 1000)
			{
				OLED_ShowNum(128 - 3 * 8, i * WORD_H, option[ErrorCountNow + i].Data, 3, OLED_8X16);
			}
			else
			{
				OLED_ShowNum(128 - 4 * 8, i * WORD_H, option[ErrorCountNow + i].Data, 4, OLED_8X16);
			}
		}
	}
#endif

#if 1
	// 光标相关显示
	if (1) // 加光标动画
	{
		CursorY_Next = CursorIndex * WORD_H;			   // 获取光标目标位置
		CursorLenNext = option[MenuIndex].NameLen * 8 + 4; // 获取下一个选项的目标宽度

		// 决定光标的Y轴移动量和方向
		if ((CursorY_Next - CursorY_Now) > 1)
		{ // 下移
			CursorY_Now += (CursorY_Next - CursorY_Now) / CursorRollSpeed + 1;
		}
		else if ((CursorY_Next - CursorY_Now) < -1)
		{ // 上移
			CursorY_Now += (CursorY_Next - CursorY_Now) / CursorRollSpeed - 1;
		}
		else
		{ // 不移动
			CursorY_Now = CursorY_Next;
		}

		// 决定光标的X轴移动量和方向
		if ((CursorLenNext - CursorLenNow) > 1)
		{
			CursorLenNow += (CursorLenNext - CursorLenNow) / CursorRollSpeed + 1;
		}
		else if ((CursorLenNext - CursorLenNow) < -1)
		{
			CursorLenNow += (CursorLenNext - CursorLenNow) / CursorRollSpeed - 1;
		}
		else
		{
			CursorLenNow = CursorLenNext;
		}
	}
	else
	{
		CursorY_Now = CursorIndex * WORD_H;
		CursorLenNow = 128;
	}

	// 显示光标
	if (CurStyle == reverse)
	{
		OLED_ReverseArea(0, CursorY_Now, CursorLenNow, WORD_H); // 反相光标
	}
	if (CurStyle == mouse)
	{
		OLED_ShowString(CursorLenNow, CursorY_Now + 5, "<-", OLED_6X8); // 尾巴光标
																		// OLED_ShowImage(CursorLenNow, CursorY_Now+6, 8, 8, Cursor);		//图片光标
	}
	if (CurStyle == frame)
	{
		OLED_DrawRectangle(0, CursorY_Now, CursorLenNow, WORD_H, 0); // 矩形光标
	}
#endif

	// OLED_ShowNum(116, 56, MenuIndex, 2, OLED_6X8); // 右下角显示选中的项;
	// OLED_Update();								   // 更新函数

	/**********************************************************/

	if (menu_Enter_event()) // 获取确认键是否被触发
	{
		if (option[MenuIndex].Next != NULL)
		{
			SetRunList = option[MenuIndex].Next;
			Ui_InitFlag = 0;
		}
		else
		{
			if (strcmp(option[MenuIndex].Name, "<<<") == 0)
			{
				SetRunList = option;
				Ui_InitFlag = 0;
				SetRunListFlag = 0;
			}
		}

		if (option[MenuIndex].func) // 如果功能不为空则执行功能,否则返回
		{
			option[MenuIndex].func();
		}
		else
		{
			return;
		}
	}
	if (menu_Back_event()) // 获取返回键键是否被触发
	{
		return;
	} // 获取按键
}
// 设置菜单运行标志
void OLED_Menu_Set_RunListFlag(uint8_t flag)
{
	SetRunListFlag = flag;
}
// 获取菜单运行标志
uint8_t OLED_Menu_Get_RunListFlag(void)
{
	return SetRunListFlag;
}
// 进入指定菜单
void OLED_Enter_Menu(Menu_t *obj)
{
	SetRunList = obj;
	Ui_InitFlag = 0;
}
// 设置对象的数据
void OLED_Obj_Set_Data(Menu_t *obj, uint16_t data)
{
	obj->Data = data;
}
// 数据的更新
__weak void OLED_DataUpdate(void)
{
}

/*  @brief  映射函数
	@param  inMin
			输入最小值
	@param  inMan
			输入最大值
	@param  outMix
			输出最小值
	@param  outMan
			输出最大值
	@param  value
			输入值
	@return 返回映射后的值
	@property 无
*/
uint8_t Mapping(uint8_t inMin, uint8_t inMan, uint8_t outMix, uint8_t outMan, uint8_t value)
{
	if (value < inMin || value > inMan)
	{
		return 0;
	}

	float percentage = (float)(value - inMin) / (inMan - inMin);			  // 百分比
	uint8_t mappedValue = (uint8_t)(percentage * (outMan - outMix) + outMix); // 映射后的值

	// printf("百分比 %.2f\n", percentage);

	return mappedValue;
}
// 进度条
void OLED_UI_Strip(uint8_t Axis_X, uint8_t Axis_Y, Menu_t *option)
{
	// 边框
	uint8_t FrameWidth = 80;  // 宽
	uint8_t FrameHeight = 18; // 高

	// 进度条 坐标
	uint8_t StripAxisValue_X = Axis_X + 2;									  // X
	uint8_t StripAxisValue_Y = Axis_Y + FrameHeight - (FrameWidth * 0.1) - 2; // Y

	// 进度条数据
	uint8_t StripData = option[MenuIndex].Data;
	// 进度条显示UI值
	uint8_t StripUI = Mapping(0, 100, 0, FrameWidth * 0.65 - 4, StripData);

	// OLED_Clear();
	OLED_ClearArea(Axis_X - 2, Axis_Y - 2, FrameWidth + 4, FrameHeight + 4);

	OLED_DrawRectangle(Axis_X, Axis_Y, FrameWidth, FrameHeight, OLED_UNFILLED); // 边框

	OLED_DrawRectangle(StripAxisValue_X, StripAxisValue_Y, FrameWidth * 0.65, FrameWidth * 0.1, OLED_UNFILLED); // 空心矩形

	if (StripData == 100)
	{
		OLED_ShowNum(StripAxisValue_X + FrameWidth * 0.65 + 2, StripAxisValue_Y, StripData, 3, OLED_6X8);
	}
	else
	{
		OLED_ShowNum(StripAxisValue_X + FrameWidth * 0.65 + 5, StripAxisValue_Y, StripData, 2, OLED_6X8);
	}
	OLED_DrawRectangle(StripAxisValue_X + 2, StripAxisValue_Y + 2, StripUI, FrameWidth * 0.1 - 4, OLED_FILLED); // 实心矩形
}
// 数据修改界面(弹窗)
void OLED_DataAlter_Show(Menu_t *option)
{
	int8_t keyValue = 0;

	if (DataAlterFlag == 1)
	{
		keyValue = menu_Roll_event();
		if (keyValue == 1)
		{
			if (option[MenuIndex].Data < 100)
				option[MenuIndex].Data += 1;
		}
		else if (keyValue == -1)
		{
			if (option[MenuIndex].Data > 0)
				option[MenuIndex].Data -= 1;
		}

		if (menu_Enter_event()) // 获取确认键是否被触发
		{
			DataAlterFlag = 0;
		}
	}
	// 动画弹出或隐藏
	if ((StripY_Next - StripY_Now) > 1)
	{
		StripY_Now += (StripY_Next - StripY_Now) / CursorRollSpeed + 1; // 隐藏
	}
	else if ((StripY_Next - StripY_Now) < -1)
	{
		StripY_Now += (StripY_Next - StripY_Now) / CursorRollSpeed - 1; // 弹出
	}
	else
	{
		StripY_Now = StripY_Next;
	}

	OLED_UI_Strip(48, StripY_Now, option);
}
/*  @brief  数据改动处理函数
	@param  Reality_Data
			要修改的真实数据
	@param  Ui_Data
			要修改的Ui数据
	@param  Flash_Addr
			Flash地址，如果不需要保存填NULL
	@return 无
	@property 无
*/
void OLED_DataAlter_Function(uint16_t *Reality_Data, uint16_t Ui_Data, uint8_t Flash_Addr)
{
	if (DataAlterFlag == 0)
	{
		DataAlterFlag = 1;
		StripY_Next = STRIPY_SHOW; // 弹出
	}
	else if (DataAlterFlag == 1)
	{
		DataAlterFlag = 0;
		StripY_Next = STRIPY_HIDE; // 隐藏
		*Reality_Data = Ui_Data;   // 数据修改
		if (Flash_Addr != NULL)
		{
			FLASH_EEPROM_Write(Flash_Addr, *Reality_Data);
		}
	}
}
/**********************************************************/
// 计算选项名宽度;
uint8_t Get_NameLen(char *String)
{
	uint8_t i = 0, len = 0;
	while (String[i] != '\0') // 遍历字符串的每个字符
	{
		if (String[i] > '~')
		{
			len += 2;
			i += 3;
		} // 如果不属于英文字符长度加2
		else
		{
			len += 1;
			i += 1;
		} // 属于英文字符长度加1
	}
	return len;
}

__weak void Chief_Frame_UI(void)
{
}

void OLED_Menu_Handle(void)
{
	OLED_Clear(); // 将OLED显存数组全部清零

	OLED_Desktop_Show(Chief_Frame_UI); // 桌面显示
	OLED_Menu_Show(SetRunList);		   // 菜单设置界面
	OLED_DataAlter_Show(SetRunList);   // 数据修改界面
	OLED_DataUpdate();
	OLED_Update(); // 更新函数
}
